1 /*
2  * The MIT License (MIT)
3  *
4  * Copyright (c) 2014 Devisualization (Richard Andrew Cattermole)
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to deal
8  * in the Software without restriction, including without limitation the rights
9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10  * copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in all
14  * copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  * SOFTWARE.
23  */
24 module devisualization.util.opengl.shaders.defs;
25 import devisualization.util.opengl.function_wrappers;
26 import gl3n.linalg;
27 deprecated("de_util:opengl is going to die"):
28 
29 class ShaderProgram {
30 	private {
31 		uint id_;
32 	}
33 	
34 	this(string vert, string frag=null, string geom=null) {
35 		import std.typecons : scoped;
36 		
37 		if (frag !is null && geom !is null) {
38 			auto vertS = scoped!Shader(vert, ShaderTypes.VertexShader);
39 			auto fragS = scoped!Shader(frag, ShaderTypes.FragmentShader);
40 			auto geomS = scoped!Shader(geom, ShaderTypes.GeometryShader);
41 			this(vertS, fragS, geomS);
42 		} else if (frag !is null) {
43 			auto vertS = scoped!Shader(vert, ShaderTypes.VertexShader);
44 			auto fragS = scoped!Shader(frag, ShaderTypes.FragmentShader);
45 			this(vertS, fragS, null);
46 		} else if (geom !is null) {
47 			auto vertS = scoped!Shader(vert, ShaderTypes.VertexShader);
48 			auto geomS = scoped!Shader(geom, ShaderTypes.GeometryShader);
49 			this(vertS, null, geomS);
50 		} else {
51 			auto vertS = scoped!Shader(vert, ShaderTypes.VertexShader);
52 			this(vertS, null, null);
53 		}
54 	}
55 	
56 	this(Shader vert = null, Shader frag = null, Shader geom = null) {
57 		// allocate the program
58 		id_ = glCreateProgram();
59 		if (vert !is null)
60 			attach(vert, false);
61 		if (frag !is null)
62 			attach(frag, false);
63 		if (geom !is null)
64 			attach(geom, false);
65 		link();
66 		bind();
67 	}
68 	
69 	~this() {
70 		// destroy the program
71 		glDeleteProgram(id_);
72 	}
73 	
74 	void attach(Shader shader, bool linkCall = true) {
75 		// attach the shader
76 		glAttachShader(id_, shader.id);
77 		if (linkCall)
78 			link();
79 	}
80 	
81 	void detach(Shader shader) {
82 		glDetachShader(id_, shader.id);
83 		link();
84 	}
85 	
86 	uint getAttribute(string name) {
87 		return glGetAttribLocation(id_, name);
88 	}
89 	
90 	uint getUniform(string name) {
91 		return glGetUniformLocation(id_, name);
92 	}
93 	
94 	@property {
95 		uint id() { return id_; }
96 	}
97 	
98 	void bind() {
99 		glUseProgram(id_);
100 	}
101 	
102 	void uniform(string name, mat2 value, bool transpose = false) {
103 		bind();
104 		glUniformMatrix2(getUniform(name), transpose, cast(float[])value.matrix);
105 	}
106 	
107 	void uniform(string name, mat3 value, bool transpose = false) {
108 		bind();
109 		glUniformMatrix3(getUniform(name), transpose, cast(float[])value.matrix);
110 	}
111 	
112 	void uniform(string name, mat4 value, bool transpose = false) {
113 		bind();
114 		glUniformMatrix4(getUniform(name), transpose, cast(float[])value.matrix);
115 	}
116 	
117 	void uniform(string name, vec2 value) {
118 		bind();
119 		glUniform(getUniform(name), cast(float[])value.vector);
120 	}
121 	
122 	void uniform(string name, vec3 value) {
123 		bind();
124 		glUniform(getUniform(name), cast(float[])value.vector);
125 	}
126 	
127 	void uniform(string name, vec4 value) {
128 		bind();
129 		glUniform(getUniform(name), cast(float[])value.vector);
130 	}
131 	
132 	void uniform(string name, float[2] value) {
133 		bind();
134 		glUniform(getUniform(name), value);
135 	}
136 	
137 	void uniform(string name, float[4] value) {
138 		bind();
139 		glUniform(getUniform(name), value);
140 	}
141 	
142 	void uniform(string name, bool value) {
143 		bind();
144 		glUniform(getUniform(name), value);
145 	}
146 	
147 	void uniform(string name, int[2] value) {
148 		bind();
149 		glUniform(getUniform(name), value);
150 	}
151 	
152 	void uniform(string name, int[4] value) {
153 		bind();
154 		glUniform(getUniform(name), value);
155 	}
156 	
157 	void uniform(string name, int value) {
158 		bind();
159 		glUniform(getUniform(name), value);
160 	}
161 	
162 	private {
163 		void link() {
164 			glLinkProgram(id_);
165 			
166 			int res;
167 			glGetProgram(id_, ProgramObjects.LinkStatus, res);
168 			if (!res)
169 				throw new Exception(getInfoLog());
170 		}
171 		
172 		string getInfoLog() {
173 			int res;
174 			glGetProgram(id_, ProgramObjects.InfoLogStatus, res);
175 			
176 			if (res > 0) {
177 				return glGetProgramInfoLog(id_);
178 			}
179 			return "";
180 		}
181 	}
182 }
183 
184 class Shader {
185 	private {
186 		//ShaderObj id_;
187 		uint id_;
188 		ShaderTypes type_;
189 	}
190 	
191 	/**
192      * Given either the source or filename(asset loader).
193      */
194 	this(string source, ShaderTypes type) {
195 		// create
196 		id_ = glCreateShader(type_);
197 		opAssign(source);
198 		type_ = type;
199 		compile();
200 	}
201 	
202 	~this() {
203 		glDeleteShader(id_);
204 	}
205 	
206 	void opAssign()(string source) {
207 		// assign
208 		glShaderSource(id_, source);
209 		compile();
210 	}
211 	
212 	@property {
213 		ShaderTypes type() { return type_; }
214 		uint id() { return id_; }
215 	}
216 	
217 	private {
218 		void compile() {
219 			// compile
220 			glCompileShader(id_);
221 			
222 			int res;
223 			glGetShader(id_, ShaderObjects.CompileStatus, res);
224 			if (!res)
225 				throw new Exception(getInfoLog());
226 		}
227 		
228 		string getInfoLog() {
229 			int res;
230 			glGetShader(id_, ShaderObjects.InfoLogLength, res);
231 			
232 			if (res > 0) {
233 				return glGetProgramInfoLog(id_);
234 			}
235 			return "";
236 		}
237 	}
238 }